/** Double-include prevention */
#if defined _mynatives_included_
  #endinput
#endif
#define _mynatives_included_

#define AbilityCap 125

new RegisteredAbilitys = 1;

new AbilityNum[MAXPLAYERS + 1];
new AbilityLevel[MAXPLAYERS + 1][AbilityCap];
new AbilityNumMaxLevel[AbilityCap];

new AbilityNumColors[AbilityCap][4];
new bool:AbilityNumColor[AbilityCap] = { false, ... };

new String:AbilityRegister[AbilityCap][32];
new String:AbilityNumName[AbilityCap][32];
new String:AbilityNumDescription[AbilityCap][128];
new String:AbilityNumUsage[AbilityCap][128];

new Handle:g_AbilityGForward;
new Handle:g_AbilityRForward;
new Handle:g_LevelCForward;

/**
 * @brief When a Ability Has Been Given To The Player
 *
 * @param		Client		A Player.
 * @param		Ability		Integer Of Ability.
 * @noreturn
 */
forward PXF_OnAbilityGiven(Client, Ability);

/**
 * @brief When a Ability Has Been Removed From The Player
 *
 * @param		Client		A Player.
 * @param		Ability		Integer Of Ability.
 * @noreturn
 */
forward PXF_OnAbilityRemoved(Client, Ability);

/**
 * @brief When a Clients Level Has Changed
 *
 * @param		Client		A Player.
 * @param		Level		NewLevel.
 * @noreturn
 */
forward PXF_OnLevelChanged(Client, Ability, NewLevel);

/**
 * @brief Sets a Players Ability
 *
 * @param Client  A Player.
 * @param Num     An Integer For The Ability.
 * @noreturn
 */
native PX_SetAbility(Client, Num);

/**
 * @brief Gets a Players Ability
 *
 * @param 		Client		A Player.
 * @return 		Integer		An Integer For The Ability.
 */
native PX_GetAbility(Client);

/**
 * @brief Sets a Players Ability Level
 *
 * @param 		Client		A Player.
 * @param 		Ability   		The Ability. 
 * @param 		Num   		The Abilitys Level.
 * @noreturn
 */
native PX_SetLevel(Client, Ability, Num);

/**
 * @brief Gets a Players Ability Level
 *
 * @param 		Client		A Player.
 * @param 		Ability   		An Integer For The Ability.
 * @return 		Integer			Integer Of Ability Level.
 */
native PX_GetLevel(Client, Ability);


/**
 * @brief Sets a Players Color Per Its Ability
 *
 * @param Client  A Player.
 * @noreturn
 */
native PX_SetPlayerColor(Client);

/**
 * @brief Sets is the Ability Has a Color
 *
 * @param 		Ability   		An Integer For The Ability.
 * @param		Bool			Uses color?
 * @noreturn
 */
native PX_AbilityUseColor(Ability, bColor);

/**
 * @brief Removes a Players Ability
 *
 * @param Client  A Player.
 * @noreturn
 */
native PX_RemoveAbilities(Client);

/**
 * @brief Sets an Abilities Color
 *
 * @param Ability  An Ability.
 * @param Int      Red.
 * @param Int      Green.
 * @param Int      Blue.
 * @param Int      Alpha.
 * @noreturn
 */
native PX_SetAbilityColor(Ability,r,g,b,a);

/**
 * @brief Sets a Players Max Ability Level
 *
 * @param 		Ability		An Ability.
 * @param 		Num   		A Maximum Level.
 * @noreturn
 */
native PX_SetAbilityMaxLevel(Ability, Num);

/**
 * @brief Gets a Players Max Ability Level
 *
 * @param 		Ability		An Ability.
 * @return 		Num   		A Maximum Level.
 */
native PX_GetAbilityMaxLevel(Ability);

/**
 * @brief Registers an ability.
 *
 * @param 		Ability		An Ability.
 * @param 		String   	A Codename.
 * @return      Integer		An AbilityID
 */
native PX_RegisterAbility(String:name[]);
native PX_RegisterAbilityNONE(String:name[]);

/**
 * @brief Gets an Abilitys by its Codename.
 *
 * @param 		String   	The Codename.
 * @noreturn
 */
native PX_GetRegisteredAbility(String:name[]);

/**
 * @brief Gets Codename by its ID.
 *
 * @param 		Integer   	The Ability.
 * @param		String		A Buffer.
 * @noreturn
 */
native PX_GetRegisteredCodename(Ability, String:buffer[]);

/**
 * @brief Returns how many abilities there is.
 *
 * @return Integer How many Abilities?
 */
native PX_RegisteredAbilitys();

/**
 * @brief Sets a Abilitys Name.
 *
 * @param 		Ability		An Ability.
 * @param 		String   	An Maximum Level.
 * @noreturn
 */
native PX_SetAbilityName(Ability, String:name[]);

/**
 * @brief Gets an Abilitys Name.
 *
 * @param 		Ability		An Ability.
 * @param 		String   	A Buffer.
 * @noreturn
 */
native PX_GetAbilityName(Ability, String:buffer[]);

/**
 * @brief Sets an Abilitys Description.
 *
 * @param 		Ability		An Ability.
 * @param 		Num   		An Description.
 * @noreturn
 */
native PX_SetAbilityDescription(Ability, const String:desc[]);

/**
 * @brief Gets an Abilitys Description.
 *
 * @param 		Ability		An Ability.
 * @param 		Num   		A Buffer.
 * @noreturn
 */
native PX_GetAbilityDescription(Ability, const String:buffer[]);

/**
 * @brief Sets an Abilitys Usage.
 *
 * @param 		Ability		An Ability.
 * @param 		Num   		A Usage.
 * @noreturn
 */
native PX_SetAbilityUsage(Ability, const String:usage[]);

/**
 * @brief Gets an Abilitys Usage.
 *
 * @param 		Ability		An Ability.
 * @param 		Num   		A Buffer.
 * @noreturn
 */
native PX_GetAbilityUsage(Ability, const String:buffer[]);

NativeIncStart()
{
	g_AbilityGForward = CreateGlobalForward("PXF_OnAbilityGiven", ET_Ignore, Param_Cell, Param_Cell);
	g_AbilityRForward = CreateGlobalForward("PXF_OnAbilityRemoved", ET_Ignore, Param_Cell, Param_Cell);
	g_LevelCForward = CreateGlobalForward("PXF_OnLevelChanged", ET_Ignore, Param_Cell, Param_Cell, Param_Cell);
}

public Native_SetAbility(Handle:plugin, numParams)
{
	decl Action:result, Action:result2;

	/* Retrieve the first parameter we receive */
	new Client = GetNativeCell(1);
	new iAbility = GetNativeCell(2);
	/* Start function call */									/* Push Params */										/* Finish function call */
	Call_StartForward(g_AbilityRForward); Call_PushCell(Client); Call_PushCell(AbilityNum[Client]); Call_Finish(_:result);
	
	AbilityNum[Client] = iAbility;
	
	/* Start function call */									/* Push Params */										/* Finish function call */
	Call_StartForward(g_AbilityGForward); Call_PushCell(Client); Call_PushCell(iAbility); Call_Finish(_:result2);
	
	return 1;

}

public Native_GetAbility(Handle:plugin, numParams)
{
	/* Retrieve the first parameter we receive */
	new Client = GetNativeCell(1);

	return AbilityNum[Client];
}

public Native_RemoveAbilities(Handle:plugin, numParams)
{
	/* Retrieve the first parameter we receive */
	new Client = GetNativeCell(1);

	AbilityNum[Client] = 0;
	CS_SetClientClanTag(Client, "None");
	
	return 1;
}

public Native_SetLevel(Handle:plugin, numParams)
{
	decl Action:result;
	new Client = GetNativeCell(1);
	new Ability = GetNativeCell(2);
	new Level = GetNativeCell(3);
	
	Call_StartForward(g_LevelCForward); Call_PushCell(Client); Call_PushCell(Ability); Call_PushCell(Level); Call_Finish(_:result);
	
	AbilityLevel[Client][Ability] = Level;
	return 1;
}

public Native_GetLevel(Handle:plugin, numParams)
{
	new Client = GetNativeCell(1);
	new Ability = GetNativeCell(2);

	return AbilityLevel[Client][Ability];
}

public Native_SetPlayerColor(Handle:Plugin, numParams)
{
	new Client = GetNativeCell(1);
	
	new i = AbilityNum[Client];
	if(AbilityNumColor[i] == true)
	{
		new r = AbilityNumColors[i][0];
		new g = AbilityNumColors[i][1];
		new b = AbilityNumColors[i][2];
		new a = AbilityNumColors[i][3];
			
		if(r == 255 && g == 255 && b == 255 && a == 255)
		{
			SetEntityRenderMode(Client, RENDER_NORMAL); 
			SetEntityRenderColor(Client,255,255,255,255);
			return 1;
		}
		SetEntityRenderMode(Client, RENDER_TRANSCOLOR);
		SetEntityRenderColor(Client,r,g,b,a);
	}
	else
	{
		SetEntityRenderMode(Client, RENDER_NORMAL); 
		SetEntityRenderColor(Client,255,255,255,255);
	}
	return 1;
}

public Native_AbilityUseColor(Handle:Plugin, numParams)
{
	new Ability = GetNativeCell(1);
	new bool:bUse = GetNativeCell(2);
	
	AbilityNumColor[Ability] = bUse;
}

public Native_SetAbilityColor(Handle:Plugin, numParams)
{
	new i = GetNativeCell(1);
	
	new r = GetNativeCell(2); 
	new g = GetNativeCell(3);
	new b = GetNativeCell(4);
	new a = GetNativeCell(5);
	
	AbilityNumColors[i][0] = r;
	AbilityNumColors[i][1] = g;
	AbilityNumColors[i][2] = b;
	AbilityNumColors[i][3] = a;
}

public Native_SetAbilityMaxLevel(Handle:plugin, numParams)
{
	new Num = GetNativeCell(1);
	AbilityNumMaxLevel[Num] = GetNativeCell(2);
}

public Native_GetAbilityMaxLevel(Handle:plugin, numParams)
{
	new Num = GetNativeCell(1);
	return AbilityNumMaxLevel[Num];
}

public Native_RegisterAbility(Handle:plugin, numParams)
{
	decl String:buffer[32];
	GetNativeString(1, buffer, sizeof(buffer));
	
	new Return = RegisteredAbilitys;
	AbilityRegister[Return] = buffer;
	RegisteredAbilitys++;
	return Return;
}

public Native_RegisterAbilityNONE(Handle:plugin, numParams)
{
	decl String:buffer[32];
	GetNativeString(1, buffer, sizeof(buffer));
	
	AbilityRegister[0] = buffer;
	return 0;
}

public Native_GetRegisteredAbility(Handle:plugin, numParams)
{
	decl String:buffer[32];
	GetNativeString(1, buffer, sizeof(buffer));
	
	new iFound = -1;
	for(new i = 0; i<RegisteredAbilitys; i++)
	{	
		if(StrEqual(buffer, AbilityRegister[i], false))
		{
			iFound = i;
		}
	}
	
	return iFound;
}

public Native_GetRegisteredCodename(Handle:plugin, numParams)
{
	new Ability = GetNativeCell(1);
	decl String:Codename[32];
	strcopy(Codename,sizeof(Codename),AbilityRegister[Ability]);
	SetNativeString(2, Codename, sizeof(Codename));
}

public Native_RegisteredAbilitys(Handle:plugin, numParams)
{
	return RegisteredAbilitys;
}

public Native_SetAbilityName(Handle:plugin, numParams)
{
	new Num = GetNativeCell(1);
	decl String:name[32];
	GetNativeString(2, name, sizeof(name));
	AbilityNumName[Num] = name;
}

public Native_GetAbilityName(Handle:plugin, numParams)
{
	new Num = GetNativeCell(1);
	decl String:name[32];
	strcopy(name,sizeof(name),AbilityNumName[Num]);
	SetNativeString(2, name, sizeof(name));
}

public Native_SetAbilityDescription(Handle:plugin, numParams)
{
	new Num = GetNativeCell(1);
	decl String:desc[128];
	GetNativeString(2, desc, sizeof(desc));
	AbilityNumDescription[Num] = desc;
}

public Native_GetAbilityDescription(Handle:plugin, numParams)
{
	new Num = GetNativeCell(1);
	decl String:desc[128];
	strcopy(desc,sizeof(desc),AbilityNumDescription[Num]);
	SetNativeString(2, desc, sizeof(desc));
}

public Native_SetAbilityUsage(Handle:plugin, numParams)
{
	new Num = GetNativeCell(1);
	decl String:usage[128];
	GetNativeString(2, usage, sizeof(usage));
	AbilityNumUsage[Num] = usage;
}

public Native_GetAbilityUsage(Handle:plugin, numParams)
{
	new Num = GetNativeCell(1);
	decl String:usage[128];
	strcopy(usage,sizeof(usage),AbilityNumUsage[Num]);
	SetNativeString(2, usage, sizeof(usage));
}

stock KeyHintText(Client, const String:szText[])
{
	new Handle:hBuffer = StartMessageOne("KeyHintText", Client); 
	BfWriteByte(hBuffer, 1); 
	BfWriteString(hBuffer, szText); 
	EndMessage();
}

stock Math_GetRandomInt(min, max)
{
	new random = GetURandomInt();
	
	if (random == 0) {
		random++;
	}

	return RoundToCeil(float(random) / (float(2147483647) / float(max - min + 1))) + min - 1;
}